/*
 * inotify-sync - a simple file synchronizer and file system watcher
 * Copyright (C) 2010-2011, inotify-sync developers and inotify-sync contributors
 * Copyright (C) 2010-2011, Cohesion Network Security Studio
 *
 * inotify-sync is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * inotify-sync is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with inotify-sync; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/*
 * FILE:			Inotify.cpp
 * USAGE:			---
 * DESCRIPTION:		---
 * OPTIONS:			---
 * REQUIREMENTS:	---
 * BUGS:			---
 * NOTES:			---
 * AUTHOR:			LI Yiwei (mail:leeyiw@gmail.com)
 * COMPANY:			---
 * VERSION:			1.0
 * CREATED:			Thu Sep  1 13:42:03 CST 2011
 * REVISION:		---
 */

#include "Inotify.h"

Inotify::Inotify(Profile &profile)
try
{
	this->profile=profile;
	fd=inotify_init();
	if(fd==-1)
		throw Error(errno,E_INOTINITFAIL);
	init_dir(profile.get_src_path());
}
catch(Error& error)
{
	error.print_error();
	exit(error.get_error_id());
}

Inotify::~Inotify()
{
	close(fd);
}

int
Inotify::init_dir(const string root_dir)
{
	s_dnode_vec.clear();
	nftw(root_dir.c_str(),
		do_init_dir,
		500,
		FTW_PHYS);
	for(size_t i=0;i<s_dnode_vec.size();i++)
		dnode_vec.push_back(s_dnode_vec.at(i));
	s_dnode_vec.clear();
	return 0;
}

void
Inotify::monitor(time_t r_time)
{
	char buf[1000]={0};
	int length=0;
	//注册中断处理程序sig_alrm
	if(signal(SIGALRM,sig_alrm)==SIG_ERR)
		return;
	//设置定时器
	if(sigsetjmp(env_alrm,1)!=0)
	{
		alarm(0);
		printf("inotify-sync: monitor time out, stop monitor!\n");
		return;
	}
	if(r_time>0)
		alarm(r_time);
	while((length=read(fd,buf,sizeof(buf)))!=-1)
	{
		int buf_offset=0;
		struct inotify_event *p_event=0,*event=0;
		while(buf_offset<length)
		{
			p_event=(struct inotify_event *)&buf[buf_offset];
			size_t event_size;
			event_size=offsetof(struct inotify_event,name)
							+p_event->len;
			event=(struct inotify_event *)malloc(event_size);
			memcpy(event,p_event,event_size);
			ievent_p_vec.push_back(event);
			buf_offset+=event_size;
		}
		if(ievent_p_vec.size()>0)
		{
			p_event_handler->handle_events(&dnode_vec,
							&ievent_p_vec);
			for(size_t i=0;i<ievent_p_vec.size();i++)
				free(ievent_p_vec.at(i));
			ievent_p_vec.clear();
		}
	}
}

void
Inotify::get_event_handler(EventHandler *p_event_handler)
{
	this->p_event_handler=p_event_handler;
}
